/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package OPC;

import Calculos.CalculaAvaliacao;
import ConexaoDados.InteracaoDados;
import java.io.*;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafish.clients.opc.JEasyOpc;
import javafish.clients.opc.JOpc;
import javafish.clients.opc.component.OpcGroup;
import javafish.clients.opc.component.OpcItem;
import javafish.clients.opc.exception.*;
import javax.swing.JOptionPane;

/**
 *
 * @author Igor
 */

/*
 * Breve Resumo: 
Grande Jan, Acredito que o código esteja prontinho, o que está faltando nele é só a avaliação do erro, 
como você comentou da possibilidade de fazer essa avaliação direto pelo banco então não implementei aquela coisa feia 
do codigo antigo onde os dados eram lidos do CSV, hehehe, deixo isso para vc se divertir no fds fazendo pelo banco, 
abaixo segue um breve resumo das funções. 
*/

public class LeituraThread {

    //Declaração de variaveis de entrada da função (Chamada de Metodo()).
    private List listaTags;    
    private String nomeServidor;    
    private String nomeHost;    
    private String nomeNo;
    private int tempoLoop;
    private int tempoAval;    
    private int servidoropc_fk;
    
    //Declaração das variaveis de condições de parada, seja pelo botão "Desconectar" ou Pelo estouro de tempo do TempoAval(Lembrando que neste ultimo caso ele continuará uma nova leitura assim que o tempo for estourado.
    private MyTask taskTimer;
    private boolean flagParada = false;
    public boolean flagParadaParcial = false;

    //Declaração de Variaveis importantes de leitura e escrita no Banco e CSV
    private BufferedReader csvBanco = null;
    private List<String> listTagsServidor = new ArrayList<>(); //Variavel responsavel pela lista de Tags oriundas do Resultset da tabela Associatag

    //Formato padrão para data que será enviada para o banco, o SQL exige que seja enviada neste formato se usarmos o TIMESTAMP, cuidado pois existe CAPS SENSE, mm é diferente de MM.
    SimpleDateFormat fdS = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Date data_atual = null;
    String data_atual_temp;
    

    

    public void IniciaLeituraTags(List ListaTags, String nomeServ, String host, String no, int tempoloop, int tempoaval, final int servidoropc_fk){                        
                
        this.listaTags = ListaTags;
        this.nomeServidor = nomeServ;
        this.nomeHost = host;
        this.nomeNo = no;
        this.tempoLoop = tempoloop;
        this.tempoAval = tempoaval;
        this.servidoropc_fk = servidoropc_fk;
        
       
               
//------------<inicialização da conexão do OPC>------------------------------------            
        JOpc.coInitialize();
         
        final JEasyOpc opc = new JEasyOpc(nomeHost, nomeServidor, "JOPC1"+Math.random());

        final OpcGroup grupo = new OpcGroup(nomeNo, true, 500, 0.0f);
        
        for (int i = 0 ; i < listaTags.size() ; i++){   
            final OpcItem item = new OpcItem(listaTags.get(i).toString().trim(), true, "");
            grupo.addItem(item);            
        }
        opc.addGroup(grupo);  
//------------<fim da inicialização do OPC>------------------------------------       
    
//-------------<Inicio da Thread>-----------------------------------------------    
        Thread LeituraTag = new Thread() {        
            
            @Override
            
            public void run() {
                                                       
                    try {
                        opc.connect();//abre conexão com o OPC                    
                        } 
                    catch (ConnectivityException ex) 
                        {
                            System.out.println("Erro na conexão OPC!!!!!");
                            pararThread();
                            Logger.getLogger(LeituraThread.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    try 
                        {
                         opc.registerGroups();// registra o grupo com as tags
                        } 
                    catch (UnableAddGroupException | UnableAddItemException ex) 
                        {
                            System.out.println("grupo não registrado!!!!!");
                            pararThread();
                            Logger.getLogger(LeituraThread.class.getName()).log(Level.SEVERE, null, ex);
                        }
            
            //Declaração do contador, isto é um timer que ficará rodando por tras do programa como se fosse uma Thread.
            
            
            //opc.start(); //inicia a conexoa OPC como uma thread
            
            
            
            try {                
                opc.asynch20Read(grupo);
                System.out.println("Conectado");
            } catch (ComponentNotFoundException | Asynch20ReadException ex) {
                Logger.getLogger(LeituraThread.class.getName()).log(Level.SEVERE, null, ex);
            }
            OpcGroup downGroup = null;
            
            //While responsavel por toda a thread, ele é que será acionado se o botão desconectar for pressionado encerrando assim toda a execução da thread.
            while(flagParada == false){
                
                Timer timer = new Timer("Contador");
                //Execução da função contadora de tempo.
                taskTimer = new MyTask();
                //Setando o tempo de estouro igual ao tempoAval.
                taskTimer.setarTempo(tempoAval);
                taskTimer.setarNomeServidor(nomeServidor);
                //Comando para ele acrescentar o incremental de segundo em segundo, schedule é contado em mS, ou seja, 60000 corresponde a 60s, que é 1 minuto. 
                timer.schedule(taskTimer, 0, 60000); //colocar 60000*60 para funcionar em Horas e 60000 para minutos           
                flagParadaParcial=false;
            
                try {
                    
                    //Modificação no local da pasta para que o programa consiga gravar sem precisar daquela manobra de 
                    //criar o arquivo primeiro para ele começar a despejar a informação, 
                    //só relembrando que antes era necessario criar o arquivo, pois, se iniciassemos o programa 
                    //sem que o arquivo já estivesse criado o programa dava erro de acesso recusado por tentar criar um 
                    //arquivo em local proibido.
                    
                    String pasta = System.getProperty("user.home");  
                    String arquivo = "/logs/"+nomeServidor+"--"+nomeHost+".csv";  
                    FileWriter writer = new FileWriter(pasta+arquivo, false);
                    
                    } 
                    catch (IOException ex) 
                    {
                        Logger.getLogger(LeituraThread.class.getName()).log(Level.SEVERE, null, ex);
                    }
               
//While responsavel pelo tempo de estouro e re-execução da classe, deixando-a em 
//loop infinito até que seja apertado o botão desconectar.
                
//-------------<Inicio do loop de Gravação no arquivo>--------------------------                
                while(taskTimer.parada()==false && flagParadaParcial == false) 
                {
                    if (opc.ping())//só faz a leitura se o servidor estiver conectado
                    {                               
                    //System.out.println("Ping:"+opc.ping()+"Running:"+opc.isRunning());                               
                        downGroup = opc.getDownloadGroup();                        
                    }
                    else{
                        System.out.println("Erro na leitura OPC!!!!!");
                    }

                    //Sleep correspondente ao loop do programa.
                   synchronized(opc){
                    try {                        
                        sleep(tempoLoop);//Espera o tempo definido no cad do servidor
                        } 
                    catch (InterruptedException ex) 
                        {
                        Logger.getLogger(LeituraThread.class.getName()).log(Level.SEVERE, null, ex);
                        }                   
                    }
                    try
                    {
                        //Explicado acima.
                        String pasta = System.getProperty("user.home");  
                        String arquivo = "/logs/"+nomeServidor+"--"+nomeHost+".csv"; 
                            try (FileWriter writer = new FileWriter(pasta+arquivo, true)) 
                            {
                               if (downGroup != null) {
                               //if (downGroup.getItems().isEmpty()==false){
                                   
                                
                                    for(int i = 0 ; i < downGroup.getItems().size() ; i++)
                                    {
                                        
                                        String valor = downGroup.getItems().get(i).toString().trim();
                                        String [] array = valor.split(";");                                                                               
                                        String [] errodeconexao = array[6].trim().split("=");                                       
                                        
                                        if (errodeconexao.length<2){
                                            array[6] = "itemValue = 0.0";
                                        }                                        
                                        writer.append(array[2].trim()+";"+array[6].trim()+";"+array[5].trim());
                                        writer.append('\r');
                                        writer.append('\n');
                                    }// fim do loop do For
                                    writer.flush();
                                    writer.close();
                                   }
                            }
                    }
                    catch(IOException e)
                    {
                        
                    } 
            } //fim do while de escrita no arquivo e tempo de avaliação atingido

//-------------<Fim do loop de Gravação no arquivo>-----------------------------
                
//Começar a leitura do arquivo com os dados do processo
                

            try {
                String pasta = System.getProperty("user.home");  
                String arquivo = "/logs/"+nomeServidor+"--"+nomeHost+".csv"; 
                csvBanco = new BufferedReader(new FileReader(pasta+arquivo));
                } 
            catch (FileNotFoundException ex) 
                {
                    Logger.getLogger(LeituraThread.class.getName()).log(Level.SEVERE, null, ex);
                }        

                String linha = "";           
                
                
                //Obtenção da Data de Inicio para povoar a tabela historiador mais na frente.
                data_atual_temp = fdS.format(new Date()); //tipo string               
                try 
                    {
                    data_atual = fdS.parse(data_atual_temp);//tipo date

                    } 
                catch (ParseException ex) 
                    {
                    Logger.getLogger(LeituraThread.class.getName()).log(Level.SEVERE, null, ex);
                    }                 
                
//Neste ponto estamos colocando todas as tags associadas a determinado servidor em uma lista.
                InteracaoDados dados = new InteracaoDados();
                ResultSet result_tagsAssociadas;
                
                try {
                    
                        result_tagsAssociadas = dados.consulta("select tbmalha_fk, NomeTag, TipoTag from associatag where servidoropc_fk="+servidoropc_fk+"");

                        while(result_tagsAssociadas.next())
                            {
                            listTagsServidor.add(result_tagsAssociadas.getString(1)+" - "+result_tagsAssociadas.getString(2)+" - "+result_tagsAssociadas.getString(3));
                            }
                        result_tagsAssociadas.close();
                    } 
                catch (SQLException ex) 
                {
                    JOptionPane.showMessageDialog(null, "Não foi possível consultar no Banco", "Erro!", JOptionPane.ERROR);   
                    Logger.getLogger(LeituraThread.class.getName()).log(Level.SEVERE, null, ex);
                }                                                
                //Fim do preenchimento da lista.
                
//Inicio da leitura do texto para povoar o banco Historiador.
//-------------<Inicio do loop de Leitura no arquivo>---------------------------
                
                while(linha!=null){
                try {
                      linha = csvBanco.readLine();//método que ler a proxima linha do arquivo                  
                    } 
                catch (IOException ex) 
                    {
                        Logger.getLogger(LeituraThread.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    
                    if(linha!=null)
                    {
                        
                        String [] valorTags = linha.split(";");                        
                        String [] valorTagsNOME = valorTags[0].split(" ");
                        String [] valorTagsVALOR = valorTags[1].split(" ");                        
                        String [] valorTagsHora = valorTags[2].split(" ");     
                        
                        //Formato de hora diferente do declarado mais acima, neste caso é só é necessario a hora, pois na horainicio já teriamos data e hora,
                        //então aqui só colocamos a hora da coleta para diferenciar coletas no mesmo instante de avaliação.
                        SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
                        Date d = null;                                                                        
                        try 
                            {
                                d = df.parse(valorTagsHora[5]);
                            } 
                            catch (ParseException ex) 
                            {
                                Logger.getLogger(LeituraThread.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        String horaColeta = null;
                        horaColeta = df.format(d);

                        //Persistencia no banco historiador, é verificado se a tag existe, e se existir quem é a malhafk e o tipo dela.
                        for(int i = 0 ; i < listTagsServidor.size() ; i++)
                        {
                            String [] vetorTagsServidor = listTagsServidor.get(i).toString().split("-");
                            
                            if(valorTagsNOME[2].trim().equals(vetorTagsServidor[1].toString().trim()))
                            {                                
                                Double valueTag = Double.parseDouble(valorTagsVALOR[2]);
                                String tipoTag = vetorTagsServidor[2].toString().trim();
                                int id_malha = Integer.parseInt(vetorTagsServidor[0].toString().trim());
                                
                                InteracaoDados gravar = new InteracaoDados();
                                try 
                                    {
                                        //Passagem de parametros são: Datainicio, Datacoleta, Tipo, Valor, malhafk.
                                        gravar.inserir_historiador(data_atual_temp, horaColeta,tipoTag , valueTag,id_malha );                                        
                                    } 
                                catch (SQLException ex) 
                                    {
                                        JOptionPane.showMessageDialog(null, "Não foi possível gravar no Banco", "Erro!", JOptionPane.ERROR);
                                        Logger.getLogger(LeituraThread.class.getName()).log(Level.SEVERE, null, ex);
                                    }
                            }// fim do if de comparação de tag´s
                        }// fim do for de leitura e escrita no banco
                        
                    }// fim do if       
                    
                }// fim do while de leitura
             // calculaITSE(data_atual_temp);
//------------<calculos de indices>----------------------------------------
                //System.out.println(listTagsServidor);       
                List<Integer> indices = new ArrayList<>();
                for(int k = 0; k<listTagsServidor.size() ; k++){
                    String [] test = listTagsServidor.get(k).toString().split("-");
                    if(indices.contains(Integer.parseInt(test[0].toString().trim())) != true){
                    indices.add(Integer.parseInt(test[0].toString().trim()));
                    }
                }
                
    CalculaGravaIndices(data_atual_temp, indices);            
    
//------------<fim calculos de indices>----------------------------------------            
    
    
                
                
//-------------<Fim do loop de Leitura no arquivo>---------------------------
            
            //taskTimer.cancel();
            listTagsServidor.clear();   
            timer.cancel();
            timer.purge();
            
            }// fim do while 

            opc.terminate();
            //opc.finalize();
            //FIM
            try 
                {
                  sleep(1);
                } 
            catch (InterruptedException ex) 
                {
                   Logger.getLogger(LeituraThread.class.getName()).log(Level.SEVERE, null, ex);
                }
            
            
            
            
        }//fim da thread




    }; 
//-------------<Fim da Thread>--------------------------------------------------
        
        LeituraTag.start(); // Inicia o processo da Thread

        JOpc.coUninitialize(); //finaliza da conexão OPC  
    }
    
    
    
    
//----------<funções auxiliares>-----------------    
    

    
    private void CalculaGravaIndices(String data, List<Integer> indices) 
    {
                
    InteracaoDados historiador = new InteracaoDados();
    CalculaAvaliacao avalia = new CalculaAvaliacao();
    
    ResultSet result;
    double IAE=0;
    double ITAE=0;
    double ITSE=0;
    double ErroMed=0;
    double PerMan=0;
    
    for(int i = 0 ; i < indices.size() ; i++){
        
    try {
        result = historiador.consulta("select distinct(tbmalha_fk) from Historiador where tbmalha_fk ="+indices.get(i)+"");
        while (result.next())
            {                
                IAE = avalia.calculaIAE(data, result.getInt("tbmalha_fk")); 
                ITAE = avalia.calculaITAE(data, result.getInt("tbmalha_fk"));
                ITSE = avalia.calculaITSE(data, result.getInt("tbmalha_fk"));
                ErroMed = avalia.calculaErroMedio(data, result.getInt("tbmalha_fk"));
                PerMan = avalia.calculaPercManual(data, result.getInt("tbmalha_fk"));
                
                historiador.inserir_avaliacao(data, IAE, ErroMed, ITSE, ITAE, PerMan, result.getInt("tbmalha_fk"));
            }//fim do while
                result.close();
        } 
    
    catch (SQLException ex) 
    {
        
//        JOptionPane.showMessageDialog(null, "Não foi possível consultar no Banco", "Erro!", JOptionPane.ERROR, null);
        Logger.getLogger(LeituraThread.class.getName()).log(Level.SEVERE, null, ex);
    }
                
    }       
                
}
        
    
    
    public void pararThread(){
        flagParada = true;        
        flagParadaParcial = true;     
    }
}




class MyTask extends TimerTask {  
    
    private int times = 0;  
    private boolean s;
    private int tempo = 4;
    private int resultado;
    private String nomeServidor = "";
    private String nomeHost = "";
    
    
    public void run(){      
        
        times++;  
        if (times <= tempo) {  
            resultado = tempo-times+1;
            System.out.println("Faltam "+resultado+" minutos/horas para acabar a Avaliação do servidor OPC "+nomeServidor+" Host:"+nomeHost);             
            s = false;
            
        } else {
            
            System.out.println("Parando e começando uma nova leitura do servidor OPC "+nomeServidor+" Host:"+nomeHost);                          
            s = true;
            times = 0;
        }          
    }
    
    public boolean parada(){
        return s;
    }
    
    public void setarTempo(int tempo){
        this.tempo = tempo;
    }
    
    public void setarNomeServidor(String nomeServidor){
        this.nomeServidor = nomeServidor;
    }
    
    
    
    
} // fim do my task
